package com.young.ums.service.impl;

import com.young.common.exception.BaseException;
import com.young.common.util.CommonUtil;
import com.young.common.core.dal.service.IDataAccessService;
import com.young.common.util.Page;
import com.young.common.util.StringUtils;
import com.young.interfaces.log.annotation.Log;
import com.young.ums.core.ETopic;
import com.young.ums.core.ISubscriber;
import com.young.ums.model.Navigate;
import com.young.ums.model.RoleNavigate;
import com.young.ums.model.RoleUser;
import com.young.ums.service.INavigateService;
import com.young.ums.service.IRoleNavigateService;
import org.springframework.stereotype.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

/**
* 角色资源服务实现
* Created by imrookie on 2018-10-9.
*/
@Service("roleNavigateService")
public class RoleNavigateServiceImpl implements IRoleNavigateService,ISubscriber {

    @Resource(name = "dataAccessService")
    IDataAccessService dataAccessService;//数据层服务

    @Resource(name="navigateService")
    INavigateService navigateService;

    private static final Logger logger = LoggerFactory.getLogger(RoleNavigateServiceImpl.class);

    private static final String MAPPER = "com.young.ums.mapper.roleNavigate";//mapper的namespace

    //获取数据列表
    @Log("查询角色资源关系")
    @Override
    public List<RoleNavigate> getList(RoleNavigate obj) {
        return dataAccessService.getList(MAPPER + ".getList", obj);
    }

    //获取数据列表(分页)
    @Log("分页查询角色资源关系")
    @Override
    public List<RoleNavigate> getPage(RoleNavigate obj, Page page) {
        return dataAccessService.getList(MAPPER + ".getList", obj, page);
    }

    //查询单条
    @Log("查询角色资源关系")
    @Override
    public RoleNavigate get(String id) {
        return dataAccessService.getObject(MAPPER + ".get", id);
    }

    //统计数量
    @Log("计数角色资源关系")
    @Override
    public int count(RoleNavigate obj) {
        return dataAccessService.getObject(MAPPER + ".count", obj);
    }

    //修改
    @Log("修改角色资源关系")
    @Override
    public int update(RoleNavigate obj) {
        return dataAccessService.update(MAPPER + ".update", obj);
    }

    //批量删除
    @Log("批量删除角色资源关系")
    @Override
    public int delete(String[] idArr) {
        int i = 0;
        for(String id : idArr){
            i += this.delete(id);
        }
        return i;
    }

    /**
     * 删除角色下所有的关联关系
     *
     * @param roleId 角色id
     * @return
     */
    @Log("根据角色删除角色资源关系")
    @Override
    public int deleteByRoleId(String roleId) {
        return dataAccessService.update(MAPPER + ".deleteByRoleId", roleId);
    }

    /**
     * 删除指定资源id关联的信息
     *
     * @param navigateId 资源id
     * @return
     */
    @Log("根据资源删除角色资源关系")
    @Override
    public int deleteByNavigateId(String navigateId) {
        return dataAccessService.update(MAPPER + ".deleteByNavigateId", navigateId);
    }

    //删除单条
    @Log("删除角色资源关系")
    @Override
    public int delete(String id) {
        return dataAccessService.delete(MAPPER + ".delete", id);
    }

    //插入
    @Log("插入角色资源关系")
    @Override
    public int insert(RoleNavigate obj) {
        if (StringUtils.isBlank(obj.getId())){
            obj.setId(CommonUtil.getUUID());
        }
        return dataAccessService.insert(MAPPER + ".insert", obj);
    }

    //批量插入
    @Log("批量插入角色资源关系")
    @Override
    public int batchInsert(List<RoleNavigate> list) {
        int i = 0;
        for(RoleNavigate item : list){
            i += this.insert(item);
        }
        return i;
    }

    /**
     * 根据角色id查询关联的资源信息列表
     *
     * @param roleIds 角色数组
     * @return
     */
    @Log("根据角色id查询关联的资源信息列表")
    @Override
    public List<Navigate> getNavigateListByRole(String[] roleIds) {
        return dataAccessService.getList(MAPPER + ".getNavigateListByRole", roleIds);
    }

    /**
     * 根据角色id查询关联的菜单类型资源列表
     * 和getNavigateListByRole方法类型,只是做了类型上的限制
     * TODO 为了效率,将类型type=1写在了sql中
     *
     * @param roleIds
     * @return
     */
    @Log("根据角色id查询关联的菜单类型资源列表")
    @Override
    public List<Navigate> getMenuNavigateListByRole(String[] roleIds) {
        return dataAccessService.getList(MAPPER + ".getMenuNavigateListByRole", roleIds);
    }

    /**
     * 根据角色id查询关联的uri类型资源列表
     *
     * @param roleIds 角色数组
     * @return
     */
    @Log("根据角色id查询关联的uri类型资源列表")
    @Override
    public List<Navigate> getUriNavigateListByRole(String[] roleIds) {
        return dataAccessService.getList(MAPPER + ".getUriNavigateListByRole", roleIds);
    }

    /**
     * 根据资源id查询关联的角色id数组
     *
     * @param navigateId 资源id
     * @return
     */
    @Log("根据资源id查询关联的角色id数组")
    @Override
    public String[] getRoleIdsByNavigateId(String navigateId) {
        List<String> list = dataAccessService.getList(MAPPER + ".getRoleIdsByNavigateId", navigateId);
        if (list != null && list.size() > 0){
            return list.toArray(new String[]{});
        }
        return null;
    }

    /**
     * 根据角色id查询关联的资源id数组
     *
     * @param roleId 角色id
     * @return
     */
    @Log("根据角色id查询关联的资源id数组")
    @Override
    public String[] getNavigateIdsByRoleId(String roleId) {
        List<String> list = dataAccessService.getList(MAPPER + ".getNavigateIdsByRoleId", roleId);
        if (list != null && list.size() > 0){
            return list.toArray(new String[]{});
        }
        return null;
    }

    /**
     * 获取资源授权树,对角色已关联的资源进行标记
     *
     * @param roleId
     * @return
     */
    @Log("获取资源授权树")
    @Override
    public List<Navigate> getNavigateListAboutGrantAuth(String roleId) {
        //查询资源
        List<Navigate> list = navigateService.getList(new Navigate());
        //查询角色已关联的资源
        String[] navigateIds = this.getNavigateIdsByRoleId(roleId);
        //若存在已关联资源,在list上进行标记
        if (navigateIds != null && navigateIds.length > 0){
            //数组转为map,使用hash来判断是否存在,优化效率
            Map<String, String> map = new HashMap<String, String>(navigateIds.length);
            for (String nid : navigateIds){
                map.put(nid, "1");
            }
            //遍历资源进行标记
            for (Navigate navigate : list){
                if (navigate != null && map.containsKey(navigate.getId())){//存在关联关系
                    navigate.setChecked(true);
                }
            }
        }

        return list;
    }

    /**
     * 批量关联资源(N)到角色(1)
     * 1.删除角色下的关联关系
     * 2.批量关联新关系
     *
     * @param roleId      角色id
     * @param navigateIds 资源id数组
     * @return
     */
    @Log("批量关联资源(N)到角色(1)")
    @Override
    public int relevanceNavigates2Role(String roleId, String[] navigateIds) {
        int i = 0;
        if (StringUtils.isBlank(roleId)){
            logger.error("[授权] 角色id为空");
            throw new BaseException("角色ID不允许为空");
        }
        //先删除
        this.deleteByRoleId(roleId);
        if (navigateIds != null && navigateIds.length > 0){
            for (String navigateId : navigateIds){
                /*//判断是否已经存在关联
                if (this.isRelevanced(roleId, navigateId)){
                    logger.info("[批量关联资源到角色] 角色[{}]与资源[{}]已经存在关联关系,跳过.", roleId, navigateId);
                    continue;
                }*/
                RoleNavigate roleNavigate = new RoleNavigate();
                roleNavigate.setRoleId(roleId);
                roleNavigate.setNavigateId(navigateId);
                i += this.insert(roleNavigate);//插入关联关系
            }
        }
        return i;
    }

    /**
     * 判断指定角色和资源是否已经关联
     *
     * @param roleId     角色id
     * @param navigateId 资源id
     * @return
     */
    @Log("判断指定角色和资源是否已经关联")
    @Override
    public boolean isRelevanced(String roleId, String navigateId) {
        RoleNavigate roleNavigate = new RoleNavigate();
        roleNavigate.setRoleId(roleId);
        roleNavigate.setNavigateId(navigateId);
        return this.count(roleNavigate) > 0;
    }

    /**
     * 判断指定角色集合是否包含xx资源的关联,存在一个角色有关联就返回true
     *
     * @param roleIds     角色id数组
     * @param navigateId 资源id
     * @return
     */
    @Log("判断指定角色集合是否包含xx资源的关联")
    @Override
    public boolean hasRelevanced(String[] roleIds, String navigateId) {
        for (String roleId : roleIds){
            if (StringUtils.isBlank(roleId) || StringUtils.isBlank(navigateId)){
                continue;
            }
            if (this.isRelevanced(roleId, navigateId)){
                return true;
            }
        }
        return false;
    }

    /**
     * 返回订阅的主题数组
     */
    @Override
    public ETopic[] topics() {
        return new ETopic[]{ETopic.ROLE_DEL, ETopic.NAVIGATE_DEL};
    }

    /**
     * 消费
     *
     * @param topic   主题
     * @param message 传输对象
     */
    @Override
    public void consume(ETopic topic, Object message) {
        try {
            if (topic == ETopic.ROLE_DEL){
                this.deleteByRoleId(message.toString());
            }else if (topic == ETopic.NAVIGATE_DEL){
                this.deleteByNavigateId(message.toString());
            }
        } catch (Exception e) {
            logger.info("[UMS消息消费-RoleNavigateServiceImpl] 消费异常,主题={},消息={}", topic, message, e);
            throw new BaseException(e);
        }
    }
}